package com.bridgeintelligent.tag.engine.mvc.service.impl;

import com.bridgeintelligent.tag.engine.api.DimItemInfo;
import com.bridgeintelligent.tag.engine.api.EngineException;
import com.bridgeintelligent.tag.engine.api.IndexNameInfo;
import com.bridgeintelligent.tag.engine.api.rsp.DimLastMonthRsp;
import com.bridgeintelligent.tag.engine.core.cache.CacheConfig;
import com.bridgeintelligent.tag.engine.core.cache.CacheUtils;
import com.bridgeintelligent.tag.engine.es.base.ESQueryUtils;
import com.bridgeintelligent.tag.engine.es.model.GroupItem;
import com.bridgeintelligent.tag.engine.mvc.service.IEsDateService;
import com.bridgeintelligent.tag.engine.mvc.service.IGroupService;
import com.bridgeintelligent.tag.engine.mvc.service.ILastMonthService;
import com.bridgeintelligent.tag.engine.mvc.service.IMonitorService;
import com.bridgeintelligent.tag.engine.parse.BaseParse;
import com.wayneleo.quickstart.framework.ExceptionCode;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
import org.elasticsearch.search.aggregations.bucket.histogram.HistogramAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.range.Range;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;

/**
 * @description 标签上个月历史
 * @author: grp 2020-10-12 10:47
 **/
@Service
@Slf4j
@AllArgsConstructor
public class LastMonthServiceImpl implements ILastMonthService,IMonitorService {

    final private IGroupService groupService;

    final private IEsDateService esDateService;

    @Override
    public DimLastMonthRsp discrete(String dimId, String queryDate) throws IOException {
        Map<String, String> timeMap = esDateService.timeSymbolRelation("1");

        String date = queryDate.replace("-","");
        //处理时间-固定标识映射字段
        if (timeMap != null && !StringUtils.isEmpty(timeMap.get(date))){
            date = timeMap.get(date);
        }
        String dimIdColumn = getDimIdColumn(dimId, date);
        BoolQueryBuilder boolQueryBuilder = getBoolQueryBuilder(dimIdColumn);
        //根据主题从缓存中获取索引名
        IndexNameInfo indexNameInfo = CacheUtils.getCacheInfo(CacheConfig.CONFIGURATION_INFO, "1");
        TermsAggregationBuilder termsBuilder =
                AggregationBuilders.terms("count").field(dimIdColumn).order(BucketOrder.count(false)).size(Integer.MAX_VALUE);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.aggregation(termsBuilder).query(boolQueryBuilder).trackTotalHits(true).size(0);
        SearchRequest searchRequest = new SearchRequest(indexNameInfo.getDataDate())
                .types(indexNameInfo.getIndexType())
                .source(searchSourceBuilder);
        SearchResponse response=
                ESQueryUtils.getClient().search(searchRequest, RequestOptions.DEFAULT);
        long total = response.getHits().getTotalHits().value;
        Aggregations aggregations =  response.getAggregations();
        Terms terms = aggregations.get("count");
        List<DimLastMonthRsp.Result> data = new ArrayList<>();
        long sum = 0L;
        int number = 0;
        for(Terms.Bucket entry : terms.getBuckets()){
            if(number>=9){
                break;
            }
            String title = Optional
                    .ofNullable((DimItemInfo) CacheUtils.getCacheInfo(CacheConfig.DIM_ITEM_INFO,
                            String.format(BaseParse.GROUP_FORMAT, dimId, entry.getKeyAsString())))
                    .map(DimItemInfo::getDimItemName)
                    .orElse(entry.getKeyAsString());
            sum += entry.getDocCount();
            data.add(DimLastMonthRsp.Result.of().setTitle(title).setCount(String.valueOf(entry.getDocCount())));
            number++;
        }
        setOthers(data, total - sum);
        return getDimLastMonthRsp(queryDate, null, response, data);
    }

    @Override
    public DimLastMonthRsp defaultGroup(String dimId, String queryDate, String type) throws IOException {
        Map<String, String> timeMap = esDateService.timeSymbolRelation("1");
        String date = queryDate.replace("-","");
        //处理时间-固定标识映射字段
        if (timeMap != null && !StringUtils.isEmpty(timeMap.get(date))){
            date = timeMap.get(date);
        }
        String dimIdColumn = dimId + "_" +date;
        // 创建请求
        if(StringUtils.equals("03", type)){
            Double interval = groupService.getNumberInterval(dimIdColumn, null,"1");
            if(interval==null){
                return getDimLastMonthRsp(queryDate, null, null, Collections.emptyList());
            }
            SearchRequest request = getNumberHistogramRequest(dimIdColumn, interval);
            return getNumberResult(request, queryDate, interval);
        }
        if(StringUtils.equals("05", type)){
            DateHistogramInterval dateInterval = groupService.getDateInterval(dimIdColumn, null,"1");
            if(dateInterval==null){
                return getDimLastMonthRsp(queryDate, null, null, Collections.emptyList());
            }
            SearchRequest request = getDateHistogramRequest(dimIdColumn, dateInterval);
            return getDateResult(request, queryDate, dateInterval);
        }
        if (StringUtils.equals("06",type)){

            return getListResult(dimId,dimIdColumn,queryDate);
        }
        throw new EngineException(new ExceptionCode(999,"不支持的统计类型"));
    }

    /**
     * 自定义分组 结果
     * @param response es响应
     * @param queryDate 查询时间
     * @return 返回结果
     */
    private DimLastMonthRsp getResult(SearchResponse response, String queryDate){
        Range terms = response.getAggregations().get("count");
        List<DimLastMonthRsp.Result> data = new ArrayList<>();
        for (Range.Bucket entry : terms.getBuckets()) {
            data.add(DimLastMonthRsp.Result.of().setTitle(entry.getKeyAsString()).setCount(String.valueOf(entry.getDocCount())));
        }
        return getDimLastMonthRsp(queryDate, null, response, data);
    }

    /**
     * 创建分组请求
     * @param dimId 标签id
     * @param date 统计日期
     * @param type 标签类型
     * @param items 分组项
     * @return es请求实体
     */
    private SearchRequest getRequest(String dimId, String date, String type, List<GroupItem> items) {
        String dimIdColumn = dimId + "_" +date;
        BoolQueryBuilder boolQueryBuilder = getBoolQueryBuilder(dimIdColumn);
        //根据主题从缓存中获取索引名
        IndexNameInfo indexNameInfo = CacheUtils.getCacheInfo(CacheConfig.CONFIGURATION_INFO, "1");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(boolQueryBuilder).trackTotalHits(true).size(0);
        if(StringUtils.equals("03", type)){
            searchSourceBuilder.aggregation(getNumberAggregation(items, dimIdColumn));
        }
        if(StringUtils.equals("05", type)){
            searchSourceBuilder.aggregation(getDateAggregation(items, dimIdColumn));
        }
        return new SearchRequest(indexNameInfo.getDataDate())
                .types(indexNameInfo.getIndexType())
                .source(searchSourceBuilder);
    }

    private SearchRequest getNumberHistogramRequest(String dimIdColumn, Double interval) {
        BoolQueryBuilder boolQueryBuilder = getBoolQueryBuilder(dimIdColumn);
        //根据主题从缓存中获取索引名
        IndexNameInfo indexNameInfo = CacheUtils.getCacheInfo(CacheConfig.CONFIGURATION_INFO, "1");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(boolQueryBuilder).trackTotalHits(true).size(0);
        HistogramAggregationBuilder builder =
                AggregationBuilders.histogram("count").field(dimIdColumn).interval(interval).minDocCount(1);
        searchSourceBuilder.aggregation(builder);
        return new SearchRequest(indexNameInfo.getDataDate())
                .types(indexNameInfo.getIndexType())
                .source(searchSourceBuilder);
    }

    private SearchRequest getDateHistogramRequest(String dimIdColumn, DateHistogramInterval interval) {
        BoolQueryBuilder boolQueryBuilder = getBoolQueryBuilder(dimIdColumn);
        //根据主题从缓存中获取索引名
        IndexNameInfo indexNameInfo = CacheUtils.getCacheInfo(CacheConfig.CONFIGURATION_INFO, "1");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(boolQueryBuilder).trackTotalHits(true).size(0);
        DateHistogramAggregationBuilder builder =
                AggregationBuilders.dateHistogram("count").field(dimIdColumn).dateHistogramInterval(interval).format(
                        "yyyy-MM-dd").minDocCount(1);
        searchSourceBuilder.aggregation(builder);
        return new SearchRequest(indexNameInfo.getDataDate())
                .types(indexNameInfo.getIndexType())
                .source(searchSourceBuilder);
    }

    public DimLastMonthRsp getListResult(String dimId,String dimIdColumn,String queryDate) {
        Set<String> fieldsSet = new HashSet<>();
        fieldsSet.add(dimIdColumn);
        BoolQueryBuilder boolQueryBuilder = getBoolQueryBuilder(dimIdColumn);
        TermsAggregationBuilder termsBuilder = AggregationBuilders.terms("count")
                .field(dimIdColumn)
                .order(BucketOrder.key(true))
                .size(Integer.MAX_VALUE);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.aggregation(termsBuilder).query(boolQueryBuilder).trackTotalHits(true).size(0);
        IndexNameInfo indexNameInfo = CacheUtils.getCacheInfo(CacheConfig.CONFIGURATION_INFO, "1");
        SearchRequest searchRequest = new SearchRequest(indexNameInfo.getDataDate()).types(indexNameInfo.getIndexType())
                .source(searchSourceBuilder);
        SearchResponse response = null;
        try {
            response = ESQueryUtils.getClient().search(searchRequest,RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.info("--------查询ES异常-------",e);
            throw new EngineException(new ExceptionCode(1001,"查询es异常"),e);
        }
        Aggregations aggregations = response.getAggregations();
        Terms terms = aggregations.get("count");
        List<DimLastMonthRsp.Result> data = new ArrayList<>();
        for (Terms.Bucket entry : terms.getBuckets()) {
            String title = Optional.ofNullable((DimItemInfo) CacheUtils.getCacheInfo(CacheConfig.DIM_ITEM_INFO,
                    String.format(BaseParse.GROUP_FORMAT,
                            dimId,
                            entry.getKeyAsString())))
                    .map(DimItemInfo::getDimItemName)
                    .orElse(entry.getKeyAsString());
            data.add(DimLastMonthRsp.Result.of().setTitle(joinStr(title,entry.getKeyAsString())).setCount(String.valueOf(entry.getDocCount())));
        }
        return DimLastMonthRsp.of().setData(DimLastMonthRsp.R.of()
                .setDate(queryDate)
                .setRecords(data)
                .setTotal(response.getHits().getTotalHits().value)
                .setInterval(""));
    }

    public String joinStr(String key,String value){
        StringBuffer buffer = new StringBuffer();
        buffer.append("").append(key).append("(").append(value).append(")");
        return buffer.toString();
    }


    @Override
    public DimLastMonthRsp customize(String dimId, String queryDate, List<GroupItem> items, String type) throws IOException {
        String date = queryDate.replace("-","");
        Map<String, String> timeMap = esDateService.timeSymbolRelation("1");
        //处理时间-固定标识映射字段
        if (timeMap != null && !StringUtils.isEmpty(timeMap.get(date))){
            date = timeMap.get(date);
        }
        // 创建请求
        SearchRequest request = getRequest(dimId, date, type, items);
        // 处理结果
        SearchResponse response=
                ESQueryUtils.getClient().search(request, RequestOptions.DEFAULT);
        return getResult(response, queryDate);
    }

    /**
     * 指标类型 默认分组查询
     * @param request 请求实体
     * @param queryDate 查询时间
     * @param interval 分组间距
     * @return 响应
     * @throws IOException es异常
     */
    private DimLastMonthRsp getNumberResult(SearchRequest request, String queryDate, Double interval) throws IOException {
        // 处理结果
        SearchResponse response=
                ESQueryUtils.getClient().search(request, RequestOptions.DEFAULT);
        Histogram histogram = response.getAggregations().get("count");
        List<DimLastMonthRsp.Result> data = new ArrayList<>();
        int number = 0;
        int other = 0;
        for (Histogram.Bucket entry : histogram.getBuckets()) {
            if(number++>=9){
                other+=entry.getDocCount();
                continue;
            }
            long key = ((Double) entry.getKey()).longValue();
            long high = key + interval.longValue();
            data.add(DimLastMonthRsp.Result.of().setTitle(key+"-"+high).setCount(String.valueOf(entry.getDocCount())));
        }
        setOthers(data, other);
        return getDimLastMonthRsp(queryDate, interval.toString(), response, data);
    }

    /**
     * 日期类型 默认分组查询
     * @param request es请求实体
     * @param queryDate 查询时间
     * @param interval 分组间距
     * @return 响应结果
     * @throws IOException es异常
     */
    private DimLastMonthRsp getDateResult(SearchRequest request, String queryDate, DateHistogramInterval interval) throws IOException {
        SearchResponse response=
                ESQueryUtils.getClient().search(request, RequestOptions.DEFAULT);
        // 处理结果
        Histogram terms = response.getAggregations().get("count");
        List<DimLastMonthRsp.Result> data = new ArrayList<>();
        int number = 0;
        int other = 0;
        for (Histogram.Bucket entry : terms.getBuckets()) {
            if(number++>=9){
                other+=entry.getDocCount();
                continue;
            }
            data.add(DimLastMonthRsp.Result.of().setTitle(getTitle(entry.getKeyAsString(), interval)).setCount(String.valueOf(entry.getDocCount())));
        }
        setOthers(data, other);
        return getDimLastMonthRsp(queryDate, interval.toString(), response, data);
    }


    private void setOthers(List<DimLastMonthRsp.Result> data, long other) {
        if(other>0){
            data.add(DimLastMonthRsp.Result.of().setTitle("其它").setCount(String.valueOf(other)));
        }
    }

    private DimLastMonthRsp getDimLastMonthRsp(String queryDate, String interval, SearchResponse response,
                                               List<DimLastMonthRsp.Result> data) {
        return DimLastMonthRsp.of().setData(DimLastMonthRsp.R.of()
                .setDate(queryDate)
                .setRecords(data)
                .setTotal(response==null?0:response.getHits().getTotalHits().value)
                .setInterval(interval));
    }
}
